/**
 * @file Lm95071.c
 *
 * Sensor de Temperatura LM95071
 *
 * @version  1.01a
 * @date     30/07/2013
 * @author   Pirx
 *
 */

/***************************** Include Files *********************************/

#include "Lm95071.h"
#include "HardEva.h"

/************************** Constant Definitions ******************************/

#define		LM95071CMDSHUTDOWN				0xffff
#define		LM95071CMDCONVERSION			0x0
#define		LM95071IDENT					0x800f

/**************************** Type Definitions ******************************/

// None

/************************** Function Prototypes *****************************/

static void WriteLm95071(UINT8 dev, UINT16 dat);				// Escritura de un Registro
static UINT16 ReadLm95071(UINT8 dev);							// Lectura de un Registro

static void Lm95071_set_dattris(UINT8 dev, _Bool _dat);			// Configurar la direccion de la Linea de Datos
static void Lm95071_set_dat(UINT8 dev, _Bool _dat);				// Establecer Linea de Datos
static _Bool Lm95071_get_dat(UINT8 dev);						// Leer Valor de la linea de Datos
static void Lm95071_set_clk(UINT8 dev, _Bool _dat);				// Establecer Linea de Clock
static void Lm95071_set_cs(UINT8 dev, _Bool _dat);				// Establecer Linea de CS

/***************************** Variable Definitions *************************/

static StrLM95071 Lm95071[1];


/******************************************************************************/
/**
* Inicializa el LM95071
*
* @param	dev Numero de Dispositivo
* @return 	None.
* @note		None.
*
******************************************************************************/
extern void Lm95071Init(UINT8 dev)
{
	Lm95071_set_cs(dev, TRUE);					// Chip Select OFF
	Lm95071[dev].Estado = Pdown;
	Lm95071[dev]._lock = FALSE;
}


/******************************************************************************/
/**
* Inicializa el LM95071
*
* @param	dev Numero de Dispositivo
* @return 	None.
* @note		None.
*
******************************************************************************/
extern void Lm95071Process(UINT8 dev)
{
	// Asegurar Lineas
	Lm95071_set_clk(dev, FALSE);					// Clock a '0'
	Lm95071_set_dattris(dev, FALSE);
	Lm95071_set_dat(dev, TRUE);

	switch (Lm95071->Estado){

		case Pdown:
			Lm95071_set_cs(dev, FALSE);				// Activar Chip Select
			ReadLm95071(dev);						// Dummy
			WriteLm95071(dev, LM95071CMDSHUTDOWN);
			Lm95071_set_cs(dev, TRUE);				// Liberar Chip
			Lm95071[dev].Estado = Ident;
		break;

		case Ident:
			Lm95071_set_cs(dev, FALSE);				// Activar Chip Select
			ReadLm95071(dev);						// Leer ID
			Lm95071_set_cs(dev, TRUE);				// Liberar Chip
			if (Lm95071[dev].DataRd == LM95071IDENT){
				Lm95071[dev].Estado = Setup;
			} else {
				Lm95071[dev]._lock = FALSE;
				Lm95071[dev].Estado = Pdown;
			}
		break;

		case Setup:
			Lm95071_set_cs(dev, FALSE);				// Activar Chip Select
			ReadLm95071(dev);						// Dummy
			WriteLm95071(dev, LM95071CMDCONVERSION);
			Lm95071_set_cs(dev, TRUE);				// Liberar Chip
			Lm95071[dev].ContRx = 0;				// Contador de Lecturas a Cero
			Lm95071[dev].Estado = Read;
		break;

		case Read:
			Lm95071_set_cs(dev, FALSE);				// Activar Chip Select
			ReadLm95071(dev);						// Leer Temperatura
			Lm95071_set_cs(dev, TRUE);				// Liberar Chip
			if ((0x3 & Lm95071[dev].DataRd) == 0x3){
				int ut;
				if ((0x8000 & Lm95071[dev].DataRd) == 0x8000){
					ut = -1 -(0xffff ^ (Lm95071[dev].DataRd));
				} else {
					ut = Lm95071[dev].DataRd;
				}
				Lm95071[dev].Celsius = (int)((ut>>2) * 3.125);
				Lm95071[dev].Fahrenheit = (((Lm95071[dev].Celsius)*9)/5) + 3200;
				//Lm95071[dev].Estado = Pdown;	// Check Device
				Lm95071[dev].ContRx = 0;
				Lm95071[dev]._lock = TRUE;
				/*if ((0x8000 & Lm95071[dev].DataRd) == 0x8000){
					Lm95071[dev].Buffer[Lm95071[dev].ContRx] = -1 -(0x3fff ^ ((Lm95071[dev].DataRd)>>2));
				} else {
					Lm95071[dev].Buffer[Lm95071[dev].ContRx] = (Lm95071[dev].DataRd)>>2;
				}
				Lm95071[dev].ContRx++;
				if (Lm95071[dev].ContRx == LM95071BUFFER){					// Fin de Buffer
					UINT8	uc;
					long int ut=0;
					// Calcular Temperatura
					for (uc=0; uc<LM95071BUFFER; uc++){
						ut += Lm95071[dev].Buffer[uc];
					}
					Lm95071[dev].Celsius = (int)((ut * 3.125) / LM95071BUFFER);
					Lm95071[dev].Fahrenheit = (((Lm95071[dev].Celsius)*9)/5) + 3200;
					Lm95071[dev].Estado = Pdown;	// Check Device
					Lm95071[dev].ContRx = 0;
					Lm95071[dev]._lock = TRUE;
				}*/
			}
			else{
				Lm95071[dev]._lock = FALSE;			// Error
				Lm95071[dev].Estado = Pdown;		// Desconectar
			}
		break;

	}

	// Asegurar Lineas
	Lm95071_set_clk(dev, TRUE);
	Lm95071_set_dattris(dev, FALSE);
	Lm95071_set_dat(dev, TRUE);
}


/******************************************************************************/
/**
* Escritura de un Registro de 16bits
*
* @param	dev Numero de Dispositivo
* @param	dat Dato de 16 bits a Escibir.
* @return 	None.
* @note		None.
*
******************************************************************************/
static void WriteLm95071(UINT8 dev, UINT16 dat)
{
	UINT16		ur = 0x8000;

	while (ur>0){
		Lm95071_set_dat(dev, ((ur & dat) == ur)? TRUE : FALSE);
		asm("nop");
		asm("nop");
		Lm95071_set_clk(dev, TRUE);					// Transferir Bit
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		Lm95071_set_clk(dev, FALSE);
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		ur >>= 1;
	}

	Lm95071[dev].DataWr = dat;						// Copia del Dato Transmitido
}


/******************************************************************************/
/**
* Lectura de un Registro de 16bits
*
* @param	dev Numero de Dispositivo
* @return 	dat Dato de 16 bits Leido.
* @note		None.
*
******************************************************************************/
static UINT16 ReadLm95071(UINT8 dev)
{
	UINT16		ur = 0x8000;
	UINT16		ud = 0x0;

	Lm95071_set_dattris(dev, TRUE);					// Poner Linea de Datos en Triestado
	asm("nop");
	asm("nop");

	while (ur>0){
		Lm95071_set_clk(dev, FALSE);				// Bajo Clock -> dato en la linea
		asm("nop");
		ud |= (Lm95071_get_dat(dev) * ur);			// Leo Dato
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		Lm95071_set_clk(dev, TRUE);					// Clock a '1'
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		ur >>= 1;
	}

	Lm95071_set_clk(dev, FALSE);					// Fin de Lectura con Clock a '0'
	Lm95071_set_dattris(dev, FALSE);				// Linea de Datos como Salida
	Lm95071[dev].DataRd = ud;						// Copia del Dato Recibido

	return ud;
}


/******************************************************************************/
/**
* Obtiene el estado de Datos Validos
*
* @param	dev Numero de Dispositivo
* @return 	_lock (TRUE = Data Valid)
* @note		None.
*
******************************************************************************/
extern _Bool Lm95071_get_lock(UINT8 dev)
{
	return Lm95071[dev]._lock;
}


/******************************************************************************/
/**
* Obtiene Los Grados Celsius
*
* @param	dev Numero de Dispositivo
* @return 	Grados Celsius en centesimas de grado
* @note		None.
*
******************************************************************************/
extern short int Lm95071_get_Celsius(UINT8 dev)
{
	return Lm95071[dev].Celsius;
}


/******************************************************************************/
/**
* Obtiene Los Grados Fahrenheit
*
* @param	dev Numero de Dispositivo
* @return 	Grados Fahrenheit en centesimas de grado
* @note		None.
*
******************************************************************************/
extern short int Lm95071_get_Fahrenheit(UINT8 dev)
{
	return Lm95071[dev].Fahrenheit;
}


/******************************************************************************/
/**
* Configurar la direccion de la Linea de Datos
*
* @param	dev Numero de Dispositivo
* @param	_dat Direccion de la linea
* @return 	None.
* @note		None.
*
******************************************************************************/
static void Lm95071_set_dattris(UINT8 dev, _Bool _dat)
{
	_tmptris = _dat;
}


/******************************************************************************/
/**
* Establecer Linea de Datos
*
* @param	dev Numero de Dispositivo
* @param	_dat Dato
* @return 	None.
* @note		None.
*
******************************************************************************/
static void Lm95071_set_dat(UINT8 dev, _Bool _dat)
{
	_tmpdo = _dat;
}


/******************************************************************************/
/**
* Leer Valor de la linea de Datos
*
* @param	dev Numero de Dispositivo
* @return	_dat Dato
* @note		None.
*
******************************************************************************/
static _Bool Lm95071_get_dat(UINT8 dev)
{
	return _tmpdi;
}


/******************************************************************************/
/**
* Establecer Linea de Clock
*
* @param	dev Numero de Dispositivo
* @param	_dat Dato
* @return 	None.
* @note		None.
*
******************************************************************************/
static void Lm95071_set_clk(UINT8 dev, _Bool _dat)
{
	_tmpclk = _dat;
}


/******************************************************************************/
/**
* Establecer Linea de CS
*
* @param	dev Numero de Dispositivo
* @param	_dat Dato
* @return 	None.
* @note		None.
*
******************************************************************************/
static void Lm95071_set_cs(UINT8 dev, _Bool _dat)
{
	_tmpcs = _dat;
}
